package com.chhuang.utils.executor;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
 * 
 * @author 黄晨
 *
 */
public class TokenFactory {
	private static TokenFactory instance;
	private Resycle resycle;
	private long enduring=1000*60*10;
	private long resycleTime=1000*60;
	protected int execMax=10;
	protected static Map<String,Token> TOKEN_MAP=new HashMap<String,Token>();
	protected static BlockingQueue<Token> TOKEN_QUEUE=new LinkedBlockingQueue<Token>();
	private TokenFactory(){
		instance=this;
	}
	private TokenFactory(int execMax){
		this.execMax=execMax;
		instance=this;
	}
	private TokenFactory(int execMax,long enduring){
		this.execMax=execMax;
		this.enduring=enduring;
		instance=this;
	}
	private TokenFactory(int execMax,long enduring,long resycleTime){
		this.execMax=execMax;
		this.enduring=enduring;
		this.resycleTime=resycleTime;
		instance=this;
	}
	public static TokenFactory getInstance(){
		if(instance==null){
			instance=new TokenFactory();
		}
		return instance;
	}
	public static TokenFactory getInstance(int execMax){
		if(instance==null){
			instance=new TokenFactory(execMax);
		}
		return instance;
	}
	public static TokenFactory getInstance(int execMax,long enduring){
		if(instance==null){
			instance=new TokenFactory(execMax,enduring);
		}
		return instance;
	}
	public String getToken(){
		createToken();
		try {
			String tokenId=TOKEN_QUEUE.take().getId();
			while(!TOKEN_MAP.containsKey(tokenId)){
				tokenId=TOKEN_QUEUE.take().getId();
			}
			return tokenId;
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return null;
	}
	public void returnToken(String tokenId){
		TOKEN_MAP.remove(tokenId);
		createToken();
	}
	protected synchronized void createToken(){
		if(resycle==null){
			resycle=new Resycle(instance,resycleTime);
			Thread thread=new Thread(resycle);
			thread.start();
		}
		ckearToken();
		while(TOKEN_MAP.size()<execMax){
			String tokenId=UUID.randomUUID().toString().replace("-", "");
			Token token=new Token();
			token.setId(tokenId);
			TOKEN_MAP.put(tokenId, token);
			TOKEN_QUEUE.add(token);
		}
	}
	private synchronized void ckearToken(){
		List<String> timeOut=new ArrayList<String>();
		for(String tokenId:TOKEN_MAP.keySet()){
			Token token=TOKEN_MAP.get(tokenId);
			if(new Date().getTime()-token.getTs()>enduring){
				timeOut.add(tokenId);
			}
		}
		for(String tokenId:timeOut){
			TOKEN_MAP.remove(tokenId);
		}
	}
	protected Resycle getResycle() {
		return resycle;
	}
	protected void setResycle(Resycle resycle) {
		this.resycle = resycle;
	}
}
